﻿using System;
using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using MugenMvvmToolkit.Models;

namespace MugenMvvmToolkit.Interfaces
{
    /// <summary>
    ///     Represents the collection that can track changes.
    /// </summary>
    public interface ITrackingCollection : IEnumerable
    {
        /// <summary>
        ///     Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.
        /// </summary>
        /// <returns>
        ///     The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.
        /// </returns>
        int Count { get; }

        /// <summary>
        ///     Gets or sets the <see cref="IStateTransitionProvider" />.
        /// </summary>
        [NotNull]
        IStateTransitionProvider StateTransitionProvider { get; set; }

        /// <summary>
        ///     Gets a value indicating whether the collection has changes, including new, deleted, or modified values.
        /// </summary>
        bool HasChanges { get; }

        /// <summary>
        ///     Determines whether the <see cref="ITrackingCollection" /> contains a specific value.
        /// </summary>
        [Pure]
        bool Contains([NotNull]object item);

        /// <summary>
        ///     Gets an array of all objects with specified entity state.
        /// </summary>
        /// <returns>
        ///     An array of objects.
        /// </returns>
        [NotNull]
        IList<T> Find<T>([NotNull]Predicate<KeyValuePair<T, EntityState>> predicate);

        /// <summary>
        ///     Gets the changes of objects.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IList{T}" />.
        /// </returns>
        [NotNull]
        IList<IEntityStateEntry> GetChanges();

        /// <summary>
        ///     Gets the changes of objects.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IList{T}" />.
        /// </returns>
        [NotNull]
        IList<IEntityStateEntry> GetChanges(EntityState entityState);

        /// <summary>
        ///     Gets a state of value.
        /// </summary>
        /// <param name="value">The specified value.</param>
        /// <returns>
        ///     An instance of <see cref="EntityState" />, if any.
        /// </returns>
        [Pure]
        EntityState GetState([NotNull]object value);

        /// <summary>
        ///     Gets a state of value.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="EntityState" />, if any.
        /// </returns>
        [Pure]
        EntityState GetState<T>([NotNull]Predicate<T> predicate);

        /// <summary>
        ///     Updates a state in the specified value.
        /// </summary>
        /// <param name="value">The specified value to update state.</param>
        /// <param name="state">The state value.</param>
        /// <param name="validateState">The flag indicating that state will be validated before assigned.</param>
        /// <returns>
        ///     If <c>true</c> state was changed; otherwise <c>false</c>.
        /// </returns>
        bool UpdateState([NotNull]object value, EntityState state, bool validateState = false);

        /// <summary>
        ///     Removes all items from the <see cref="ITrackingCollection" />.
        /// </summary>
        void Clear();

        /// <summary>
        ///     Clones the structure of the <see cref="ITrackingCollection" />.
        /// </summary>
        /// <returns>
        ///     A new <see cref="ITrackingCollection" /> with the same schema as the current <see cref="ITrackingCollection" />.
        /// </returns>
        ITrackingCollection Clone();
    }

    /// <summary>
    ///     Represents the collection that can track changes.
    /// </summary>
    /// <typeparam name="T">The type of object.</typeparam>
    public interface ITrackingCollection<T> : IEnumerable<T>, ITrackingCollection where T : class
    {
        /// <summary>
        ///     Determines whether the <see cref="ITrackingCollection{T}" /> contains a specific value.
        /// </summary>
        bool Contains([NotNull]T item);

        /// <summary>
        ///     Gets an array of all objects with specified entity state.
        /// </summary>
        /// <returns>
        ///     An array of objects.
        /// </returns>
        [NotNull]
        IList<T> Find([NotNull]Predicate<KeyValuePair<T, EntityState>> predicate);

        /// <summary>
        ///     Gets the changes of objects.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IList{T}" />.
        /// </returns>
        [NotNull]
        new IList<IEntityStateEntry<T>> GetChanges();

        /// <summary>
        ///     Gets the changes of objects.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IList{T}" />.
        /// </returns>
        [NotNull]
        new IList<IEntityStateEntry<T>> GetChanges(EntityState entityState);

        /// <summary>
        ///     Gets a state of value.
        /// </summary>
        /// <param name="value">The specified value.</param>
        /// <returns>
        ///     An instance of <see cref="EntityState" />, if any.
        /// </returns>
        [Pure]
        EntityState GetState([NotNull]T value);

        /// <summary>
        ///     Gets a state of value.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="EntityState" />, if any.
        /// </returns>
        [Pure]
        EntityState GetState([NotNull]Predicate<T> predicate);

        /// <summary>
        ///     Updates a state in the specified value.
        /// </summary>
        /// <param name="value">The specified value to update state.</param>
        /// <param name="state">The state value.</param>
        /// <param name="validateState">The flag indicating that state will be validated before assigned.</param>
        /// <returns>
        ///     If <c>true</c> state was changed; otherwise <c>false</c>.
        /// </returns>
        bool UpdateState([NotNull]T value, EntityState state, bool validateState = false);
    }
}